///*
//* $Id: paex_record.c 1752 2011-09-08 03:21:55Z philburk $
//*
//* This program uses the PortAudio Portable Audio Library.
//* For more information see: http://www.portaudio.com
//* Copyright (c) 1999-2000 Ross Bencina and Phil Burk
//*
//* Permission is hereby granted, free of charge, to any person obtaining
//* a copy of this software and associated documentation files
//* (the "Software"), to deal in the Software without restriction,
//* including without limitation the rights to use, copy, modify, merge,
//* publish, distribute, sublicense, and/or sell copies of the Software,
//* and to permit persons to whom the Software is furnished to do so,
//* subject to the following conditions:
//*
//* The above copyright notice and this permission notice shall be
//* included in all copies or substantial portions of the Software.
//*
//* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
//* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
//* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
//* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
//* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
//* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
//* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//*/
//
///*
//* The text above constitutes the entire PortAudio license; however, 
//* the PortAudio community also makes the following non-binding requests:
//*
//* Any person wishing to distribute modifications to the Software is
//* requested to send the modifications to the original developer so that
//* they can be incorporated into the canonical version. It is also 
//* requested that these non-binding requests be included along with the 
//* license above.
//*/
//
//#include "Audio.h"
//#include "Log.h"
//#include "exception.h"
//
///* This routine will be called by the PortAudio engine when audio is needed.
//** It may be called at interrupt level on some machines so don't do anything
//** that could mess up the system like calling malloc() or free().
//*/


#include "Audio.h"
#include "AudioStream.h"
#include "../Speex/Speex/speex.h"
#include "../PortAudio/portaudio/portaudio.h"


static int recordCallback(	const void *inputBuffer, void *outputBuffer,
							unsigned long framesPerBuffer,
							const PaStreamCallbackTimeInfo* timeInfo,
							PaStreamCallbackFlags statusFlags,
							void *userData )
{
	paTestData *data = (paTestData*)userData;
	const SAMPLE *rptr = (const SAMPLE*)inputBuffer;
	const SAMPLE *rptr1 = (const SAMPLE*)inputBuffer;
	SAMPLE *optr = (SAMPLE*)outputBuffer;

	SAMPLE *wptr = &data->recordedSamples[data->frameIndex * NUM_CHANNELS];
	long framesToCalc;
	long i;
	int finished;
	unsigned long framesLeft = data->maxFrameIndex - data->frameIndex;

	(void) outputBuffer; /* Prevent unused variable warnings. */
	(void) timeInfo;
	(void) statusFlags;
	(void) userData;

	if( framesLeft < framesPerBuffer )
	{
		framesToCalc = framesLeft;
		finished = paComplete;
	}
	else
	{
		framesToCalc = framesPerBuffer;
		finished = paContinue;
	}

	if( inputBuffer == NULL )
	{
		for( i=0; i<framesToCalc; i++ )
		{
			*wptr++ = SAMPLE_SILENCE;  /* left */
			if( NUM_CHANNELS == 2 )
				*wptr++ = SAMPLE_SILENCE;  /* right */
		}
	}
	else
	{
		for( i=0; i<framesToCalc; i++ )
		{
			*wptr++ = *rptr++;  /* left */
			if( NUM_CHANNELS == 2 )
				*wptr++ = *rptr++;  /* right */
		}
	}
	data->frameIndex += framesToCalc;
	/*if (data->frameIndex >= data->maxFrameIndex){
		data->frameIndex = 0;
		finished = paContinue;
	}*/
	return finished;
}

///* This routine will be called by the PortAudio engine when audio is needed.
//** It may be called at interrupt level on some machines so don't do anything
//** that could mess up the system like calling malloc() or free().
//*/
static int playCallback(const void *inputBuffer,
						void *outputBuffer,
						unsigned long framesPerBuffer,
						const PaStreamCallbackTimeInfo* timeInfo,
						PaStreamCallbackFlags statusFlags,
						void *userData)
{
	paTestData *data = (paTestData*)userData;
	SAMPLE *rptr = &data->recordedSamples[data->frameIndex * NUM_CHANNELS];
	SAMPLE *wptr = (SAMPLE*)outputBuffer;
	unsigned int i;
	int finished;
	unsigned int framesLeft = data->maxFrameIndex - data->frameIndex;

	(void) inputBuffer; /* Prevent unused variable warnings. */
	(void) timeInfo;
	(void) statusFlags;
	(void) userData;

	if( framesLeft < framesPerBuffer )
	{
		/* final buffer... */
		for( i=0; i<framesLeft; i++ )
		{
			*wptr++ = *rptr++;  /* left */
			if(NUM_CHANNELS == 2)
				*wptr++ = *rptr++;  /* right */
		}
		for( ; i<framesPerBuffer; i++ )
		{
			*wptr++ = 0;  /* left */
			if( NUM_CHANNELS == 2 )
				*wptr++ = 0;  /* right */
		}
		data->frameIndex += framesLeft;
		data->frameIndex = 0;
		finished = paContinue;
	}
	else
	{
		for( i=0; i < framesPerBuffer; i++ )
		{
			*wptr++ = *rptr++;  /* left */
			if(NUM_CHANNELS == 2)
				*wptr++ = *rptr++;  /* right */
		}
		data->frameIndex += framesPerBuffer;
		finished = paContinue;
	}
	return finished;
}
//
///*******************************************************************/
//int main(void);
//int main(void)
//{
//	PaStreamParameters  inputParameters,
//	outputParameters;
//	PaStream*           stream;
//	PaError             err = paNoError;
//	paTestData          data;
//	int                 i;
//	int                 totalFrames;
//	int                 numSamples;
//	int                 numBytes;
//	SAMPLE              max, val;
//	double              average;
//
//	printf("patest_record.c\n"); fflush(stdout);
//
//	data.maxFrameIndex = totalFrames = NUM_SECONDS * SAMPLE_RATE; /* Record for a few seconds. */
//	data.frameIndex = 0;
//	numSamples = totalFrames * NUM_CHANNELS;
//	numBytes = numSamples * sizeof(SAMPLE);
//	data.recordedSamples = (SAMPLE *) malloc( numBytes ); /* From now on, recordedSamples is initialised. */
//	
//	try {
//		if(data.recordedSamples == NULL )
//			throw exception("data.recordedSamples", "Could not allocate record array.", __LINE__);
//	}
//	catch(exception e) {	e.where();	e.what();	}
//
//	for( i=0; i<numSamples; i++ )
//		data.recordedSamples[i] = 0;
//
//	try {
//		err = Pa_Initialize();
//		//if (err != paNoError)
//			throw exception("Initialize", "Pa_Initialize failed", __LINE__);
//	}
//	catch(exception e) {	e.where();	e.what();	}
//
//
//	/*
//	** INITIALISATION DE L'INPUT PARAMETERS
//	*/
//
//	inputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */
//	try{
//		if (inputParameters.device == paNoDevice)
//			throw exception("inputParameters.device", "Error: No default input device.", __LINE__);
//	}
//	catch(exception e) {	e.where();	e.what();	}
//
//	inputParameters.channelCount = 2;                    /* stereo input */
//	inputParameters.sampleFormat = PA_SAMPLE_TYPE;
//	inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency;
//	inputParameters.hostApiSpecificStreamInfo = NULL;
//
//	/*
//	** INITIALISATION DES OUTPUTS PARAMETERS
//	*/
//	outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
//	try{
//		if (outputParameters.device == paNoDevice)
//			throw exception("outputParameters.device", "Error: No default output device.", __LINE__);
//	}
//	catch(exception e) {	e.where();	e.what();	}
//
//	outputParameters.channelCount = 2;                     /* stereo output */
//	outputParameters.sampleFormat =  PA_SAMPLE_TYPE;
//	outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;
//	outputParameters.hostApiSpecificStreamInfo = NULL;
//
//	/* Record some audio. -------------------------------------------- */
//	err = Pa_OpenStream(&stream,
//						&inputParameters,
//						&outputParameters, /* &outputParameters, */
//						SAMPLE_RATE,
//						FRAMES_PER_BUFFER,
//						paClipOff,      /* we won't output out of range samples so don't bother clipping them */
//						recordCallback,
//						&data);
//	if(err != paNoError)
//		goto done;
//
//
//	err = Pa_StartStream(stream);
//	if(err != paNoError)
//		goto done;
//	printf("\n=== Now recording!! Please speak into the microphone. ===\n"); fflush(stdout);
//
//	while((err = Pa_IsStreamActive(stream)) == 1)
//	{ 
//		Pa_Sleep(1000);
//		printf("index = %d\n", data.frameIndex ); fflush(stdout);
//	}
//	if( err < 0 )
//		goto done;
//
//
//	/* Playback recorded data.  -------------------------------------------- */
//	data.frameIndex = 0;
//
//	printf("\n=== Now playing back. ===\n"); fflush(stdout);
//	err = Pa_OpenStream(
//	&stream,
//	NULL, /* no input */
//	&outputParameters,
//	SAMPLE_RATE,
//	FRAMES_PER_BUFFER,
//	paClipOff,      /* we won't output out of range samples so don't bother clipping them */
//	playCallback,
//	&data );
//	if( err != paNoError ) goto done;
//
//	if(stream)
//	{
//		err = Pa_StartStream( stream );
//		if( err != paNoError ) goto done;
//			printf("Waiting for playback to finish.\n"); fflush(stdout);
//
//		while(( err = Pa_IsStreamActive( stream ) ) == 1 )
//			Pa_Sleep(100);
//		if( err < 0 ) goto done;
//			err = Pa_CloseStream( stream );
//		if( err != paNoError ) goto done;
//			printf("Done.\n"); fflush(stdout);
//	}
//
//	done:
//	Pa_Terminate();
//	if( data.recordedSamples )       /* Sure it is NULL or valid. */
//		free( data.recordedSamples );
//	if( err != paNoError )
//	{
//		fprintf( stderr, "An error occured while using the portaudio stream\n" );
//		fprintf( stderr, "Error number: %d\n", err );
//		fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
//		err = 1;          /* Always return 0 or 1, but no other return codes. */
//	}
//	return err;
//}



int main(void){

	PaStreamParameters  inputParameters, outputParameters;
	PaError             err = paNoError;
	paTestData          data;
	int                 i;
	int                 totalframes;
	int                 numsamples;
	int                 numbytes;
	SAMPLE              max, val;
	double              average;
	short				*sampleBlock_short;
	SAMPLE				*sampleBlock;

	int                 totalFrames;


	data.maxFrameIndex = totalFrames = NUM_SECONDS * SAMPLE_RATE;
	data.frameIndex = 0;
	int numSamples = totalFrames * NUM_CHANNELS;
	int numBytes = numSamples * sizeof(SAMPLE);
	data.recordedSamples = (SAMPLE *) malloc(numBytes);
	for( i=0; i<numSamples; i++ ) data.recordedSamples[i] = 0;
	
	Audio				*audio = new	Audio();

	audio->Initialize();

		
    /* -- setup input and output -- */
    inputParameters.device						=	Pa_GetDefaultInputDevice(); /* default input device */
    inputParameters.channelCount				=	NUM_CHANNELS;
    inputParameters.sampleFormat				=	PA_SAMPLE_TYPE;
    inputParameters.suggestedLatency			=	Pa_GetDeviceInfo( inputParameters.device )->defaultHighInputLatency ;
    inputParameters.hostApiSpecificStreamInfo	=	NULL;
		
    outputParameters.device						=	Pa_GetDefaultOutputDevice(); /* default output device */
    outputParameters.channelCount				=	NUM_CHANNELS;
    outputParameters.sampleFormat				=	PA_SAMPLE_TYPE;
    outputParameters.suggestedLatency			=	Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency;
    outputParameters.hostApiSpecificStreamInfo	=	NULL;
	
	sampleBlock_short = (short*)malloc(NUM_SECONDS * SAMPLE_RATE + 1);
	sampleBlock	= (SAMPLE*)malloc(NUM_SECONDS * SAMPLE_RATE + 1);
	
	
	void *input = reinterpret_cast<void*>(&inputParameters);
	void *output = reinterpret_cast<void*>(&outputParameters);
	AudioStream *inStream = audio->OpenStream(_INPUT_, input, recordCallback, &data);
	AudioStream *outStream = audio->OpenStream(_OUTPUT_, output, playCallback, &data);
	

	inStream->Start();


	float		buffer[FRAMES_PER_BUFFER];
	char		cbits[FRAMES_PER_BUFFER + 40];
	int			nbBytes;
	void		*state_encode, *state_decode;
	
	//SpeexBits	bits,bits1;
	//const		SpeexMode* my_speex_nb_mode = speex_lib_get_mode(1);

	// INITIALISATION ENCODE
	/*state_encode	=	speex_encoder_init(my_speex_nb_mode);
	int	tmp_encode	=	8;
	speex_encoder_ctl(state_encode, SPEEX_SET_QUALITY, &tmp_encode);*/
	// END //

	// INITIALISATION DECODE
	/*state_decode	=	speex_decoder_init(my_speex_nb_mode);
	int tmp_decode	=	1;
	speex_decoder_ctl(state_decode, SPEEX_SET_ENH, &tmp_decode);*/
	// END //
	
	/*speex_bits_init(&bits);*/
	max = 0;
	average = 0.0;
	while((err = inStream->IsActive()) == 1 )
	{
		Pa_Sleep(1000);
		printf("index = %d\n", data.frameIndex ); fflush(stdout);
	}
	inStream->Stop();
	outStream->Start();
	while((err = outStream->IsActive()) == 1 )
	{
		Pa_Sleep(1000);
		printf("index = %d\n", data.frameIndex ); fflush(stdout);
	}
	//for( i=0; i<(60*SAMPLE_RATE)/FRAMES_PER_BUFFER; ++i)
 //   {
	//	val = data.recordedSamples[i];
	//	if( val < 0 ) val = -val; /* ABS */
	//	if( val > max ){
	//		max = val;
	//	}
	//	average += val;


	//	/*speex_bits_reset(&bits);*/

	//	// ENCODAGE
	//	/*for (int j = 0; j < FRAMES_PER_BUFFER; ++j){
	//		sampleBlock[j] = sampleBlock_short[j];
	//	}
	//	speex_encode(state_encode, sampleBlock, &bits);
	//	nbBytes = speex_bits_write(&bits, cbits, FRAMES_PER_BUFFER + 40);
	//	
	//	
	//	for (int j = 0; j < FRAMES_PER_BUFFER; ++j){
	//		sampleBlock[j] = 0.0;
	//	}*/

	//	//DECODAGE
	///*	speex_bits_read_from(&bits, cbits, nbBytes);
	//	speex_decode(state_decode, &bits, sampleBlock);*/

	//	//for (int j = 0; j < FRAMES_PER_BUFFER; ++j){
	//	//	//sampleBlock_short[j] = sampleBlock[j];
	//	//}
	//}
	
   /*speex_encoder_destroy(state_encode);*/
   /*speex_decoder_destroy(state_decode);

   speex_bits_destroy(&bits);*/
   
	outStream->Stop();
	
	audio->CloseStream(inStream);
	//audio->CloseStream(outStream);
	audio->Terminate();

	//audio->StartStream();
	//std::cout << "Wire on. Will run one minute." << std::endl;
	// 
	//for( i=0; i<(60*SAMPLE_RATE)/FRAMES_PER_BUFFER; ++i )
 //   {
 //      audio->Write(sampleBlock, FRAMES_PER_BUFFER);
	//   audio->Read(sampleBlock, FRAMES_PER_BUFFER);
 //   }

	//audio->StopStream();
	//audio->CloseStream();
	//audio->Terminate();
	//delete audio;
	//return 0;

 //   err = Pa_Initialize();
	//sampleBlock = (SAMPLE*)malloc(NUM_SECONDS * SAMPLE_RATE + 1);
	//


 //   /* -- setup stream -- */
 //   err = Pa_OpenStream(
 //             &stream,
 //             &inputParameters,
 //             &outputParameters,
 //             SAMPLE_RATE,
 //             FRAMES_PER_BUFFER,
 //             paClipOff,      /* we won't output out of range samples so don't bother clipping them */
 //             NULL, /* no callback, use blocking API */
 //             NULL ); /* no callback, so no callback userData */

 //   /* -- start stream -- */
 //   err = Pa_StartStream( stream );
 //   printf("Wire on. Will run one minute.\n"); fflush(stdout);

 //   /* -- Here's the loop where we pass data from input to output -- */
 //   for( i=0; i<(60*SAMPLE_RATE)/FRAMES_PER_BUFFER; ++i )
 //   {
 //      err = Pa_WriteStream( stream, sampleBlock, FRAMES_PER_BUFFER );
 //      err = Pa_ReadStream( stream, sampleBlock, FRAMES_PER_BUFFER );
 //   }
 //   /* -- Now we stop the stream -- */
 //   err = Pa_StopStream( stream );

 //   /* -- don't forget to cleanup! -- */
 //   err = Pa_CloseStream( stream );

 //   Pa_Terminate();
 //   return 0;
}